package com.ap.core.jbehave.confirmpayment.mcom.quickpay;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;

import org.hamcrest.CoreMatchers;
import org.jbehave.core.annotations.Given;
import org.jbehave.core.annotations.Then;
import org.jbehave.core.annotations.When;

import com.ap.core.cxf.jaxb.common.DeliveryType;
import com.ap.core.cxf.jaxb.common.ResponseWithIntentType;
import com.ap.core.cxf.jaxb.managepayment.ConfirmPayment1Request;
import com.ap.core.cxf.jaxb.managepayment.ConfirmPayment1Response;
import com.ap.core.cxf.jaxb.managepayment.RTPSummaryType;
import com.ap.core.cxf.jaxb.managepayment.RetrieveRTP1Request;
import com.ap.core.cxf.jaxb.managepayment.RetrieveRTP1Response;
import com.ap.core.cxf.jaxb.managertp.SubmitRTP1Request;
import com.ap.core.cxf.jaxb.managertp.SubmitRTP1Response;
import com.ap.core.cxf.jaxb.managertp.SubmitRTPMessageType;
import com.ap.core.cxf.jaxb.msghdr.MessageType;
import com.ap.core.cxf.jaxb.rtp.RTPSenderInfoType;
import com.ap.core.cxf.jaxb.rtp.TransactionCheckOutType;
import com.ap.core.jbehave.BaseTransitionRTPSteps;
import com.ap.core.jbehave.StoryContext;
import com.ap.core.util.JaxbUtil;
import com.ap.core.util.Nullable;
import com.ap.core.util.TypedKey;
import com.core.ap.wsdl.managepaymentservice_1.ConfirmPayment1Fault;
import com.core.ap.wsdl.managepaymentservice_1.ManagePayment1PortType;
import com.core.ap.wsdl.managertpservice_1.ManageRTP1PortType;

public class EcomQuickPayEndToEndSteps extends BaseTransitionRTPSteps {

	private static final TypedKey<Nullable<RetrieveRTP1Response>> RETRIEVE_RTP_RESPONSE  = new TypedKey<>("RetreiveRTPResponseType");
	private static final TypedKey<Nullable<ConfirmPayment1Response>> CONFIRM_PAYMENT_RESPONSE  = new TypedKey<>("ConfirmPaymentResponseType");
    protected static final TypedKey<Nullable<SubmitRTP1Response>> SubmitRTP1Response = new TypedKey<>("ResponseRTPType");
    public static final TypedKey<RTPSummaryType> RTP_SUMMARY = new TypedKey<>("RTP Summary");
    public static final TypedKey<RTPSenderInfoType> RTP_SENDER_INFO = new TypedKey<>("RTP Sender Info");
    public static final TypedKey<String> RTP_MSGTYPE = new TypedKey<>("RTP Message Type");

	private SubmitRTP1Request submitRTPRequest;
    SubmitRTP1Response responseRTPType;
    private RetrieveRTP1Request retrieveRTPRequest;
	private ConfirmPayment1Request confirmPayment1Request;

	public EcomQuickPayEndToEndSteps(StoryContext storyContext) {
        super(storyContext);
	}

	@Given("the consumer has chosen to pay by Zapp quick pay checkout meathod on a merchant's e-com site")
	public void giveZappQuickPay() throws Exception {
        submitRTPRequest = createSubmitRTPRequest(SubmitRTPMessageType.SUBMITRTPFORBRN);
        submitRTPRequest.getRTPSenderInfo().getDistributorInfo().setDistributorId("000001");
        submitRTPRequest.getRTPSenderInfo().getDetailMerchantInfo().getMerchantInfo().setMerchantId("000001");

        submitRTPRequest.getRTPSummary().setTxCheckout(TransactionCheckOutType.QKPACHK);
        submitRTPRequest.getDelivery().setDeliveryAddress(null);
       // submitRTPRequest.getDelivery().setDeliveryType(DeliveryType.DELTAD);
        LOG.info("When -  a Consumer chooses to make payment using AP service through m-com site to purchase a digital product");
        JaxbUtil.newInstance().javaToXML(SubmitRTP1Request.class, submitRTPRequest);
	}

    @Given("the consumer has chosen to pay by Zapp quick pay checkout meathod on a merchant's e-com site with deliverty type as DIGDEL")
    public void giveZappQuickPayWithDigDel() throws Exception {
        submitRTPRequest = createSubmitRTPRequest(SubmitRTPMessageType.SUBMITRTPFORBRN);
        submitRTPRequest.getRTPSenderInfo().getDistributorInfo().setDistributorId("000001");
        submitRTPRequest.getRTPSenderInfo().getDetailMerchantInfo().getMerchantInfo().setMerchantId("000001");

        submitRTPRequest.getRTPSummary().setTxCheckout(TransactionCheckOutType.QKPACHK);
        submitRTPRequest.getDelivery().setDeliveryAddress(null);
        submitRTPRequest.getDelivery().setDeliveryType(DeliveryType.DIGDEL);
        LOG.info("When -  a Consumer chooses to make payment using AP service through m-com site to purchase a digital product");
        JaxbUtil.newInstance().javaToXML(SubmitRTP1Request.class, submitRTPRequest);
    }


    @When("the distributor submits a structurally valid request with RTP details")
	public void whenAPReceivesSubmitRTPRequest() throws Exception {
        final ManageRTP1PortType singnedPort = factory.getBean(ManageRTP1PortType.class);
        responseRTPType = singnedPort.submitRTP1(submitRTPRequest);
        System.out.println("Response Received from server: " + System.currentTimeMillis());
        LOG.info("When -  Response Received");
        JaxbUtil.newInstance().javaToXML(SubmitRTP1Response.class, responseRTPType);

        storyContext.put(SubmitRTP1Response, Nullable.nullable(responseRTPType));
	}


    @Then("all RTP information is stored with a system timestamp")
	public void thenAPSendsSubmitRTP() {

	}

    @Then("APCore generates the unique AP Trnasaction ID, APTransaction Retrieval ID, ReconID and the BRN")
    public void thenAPTransactionIdGenerated() {
        Nullable<SubmitRTP1Response> responseRTPType = storyContext.get(SubmitRTP1Response);
        assertThat("Didn't receive ResponseWithIntentType", false, CoreMatchers.is(equalTo(responseRTPType.hasNull())));

        final ResponseWithIntentType responseWithIntentType = responseRTPType.value().getResponseInfo();
        assertThat("APTransactionId is not as expected", false, CoreMatchers.is(equalTo(responseWithIntentType.getApTransactionId() == null)));
        assertThat("APTransactionRetrievalId is not as expected", false, CoreMatchers.is(equalTo(responseWithIntentType.getApTRId() == null)));

        assertThat("Didn't receive ResponseWithIntentType", false, CoreMatchers.is(equalTo(responseRTPType.hasNull())));

        assertThat("ReconId is not as expected", false, CoreMatchers.is(equalTo(responseWithIntentType.getReconId() == null)));

        assertThat("BRN is not as expected", false, CoreMatchers.is(equalTo(responseWithIntentType.getBRN() == null)));
    }

    @Then("a successful response message is to be created and sent to the OSB")
    public void thenResponseCreated() {
        Nullable<SubmitRTP1Response> responseRTPType = storyContext.get(SubmitRTP1Response);
        doSubmitRTPResponseAssertions(responseRTPType, submitRTPRequest);
    }

    @Then("status of the RTP submitted is updated to AWAITING_RETRIEVAL")
    public void thenRTPSubmitted() {
    }




    @Given("the consumer logs into the mobile app successfully and enters the correct BRN")
    public void giveConsumerLogsinMobileApp() throws Exception {

        retrieveRTPRequest = createRetrieveRTPRequest();
        retrieveRTPRequest.getRequestInfo().setFIId("000002");
        retrieveRTPRequest.getRequestInfo().setFIConsumerId("hsbccon2");
        if(null == responseRTPType.getResponseInfo().getBRN()){
			 retrieveRTPRequest.getRequestInfo().setApTransactionId(responseRTPType.getResponseInfo().getApTransactionId());
			 retrieveRTPRequest.getRequestInfo().setApTRId(responseRTPType.getResponseInfo().getApTRId());
			 retrieveRTPRequest.getRequestInfo().setBRN(null); 
        }else{
        	retrieveRTPRequest.getRequestInfo().setApTransactionId(null);
        	retrieveRTPRequest.getRequestInfo().setApTRId(null);
        	retrieveRTPRequest.getRequestInfo().setBRN(responseRTPType.getResponseInfo().getBRN());            
        }
        
        JaxbUtil.newInstance().javaToXML(RetrieveRTP1Request.class, retrieveRTPRequest);

    }


    @When("Consumer's FI sends the structurally valid request to Retrieve previously submitted RTP to AP Core")
    public void whenAPReceivesValidRetrieveRequest() throws Exception {
        LOG.info("When -  the consumer has been authenticated");

        final ManagePayment1PortType singnedPort = factory.getBean(ManagePayment1PortType.class);

        RetrieveRTP1Response retrieveRTPResponse = singnedPort.retrieveRTP1(retrieveRTPRequest);
        LOG.info("When -  Response Received");
        JaxbUtil.newInstance().javaToXML(RetrieveRTP1Response.class, retrieveRTPResponse);

        if (retrieveRTPResponse != null) {
            if (retrieveRTPResponse.getRTPSummary() != null) {
                storyContext.put(RTP_SUMMARY, retrieveRTPResponse.getRTPSummary());
            }
            if (retrieveRTPResponse.getRTPSenderInfo() != null) {
                storyContext.put(RTP_SENDER_INFO, retrieveRTPResponse.getRTPSenderInfo());
            }
            if (retrieveRTPResponse.getMsgHdr() != null) {
                storyContext.put(RTP_MSGTYPE, retrieveRTPResponse.getMsgHdr().getMsgType().toString());
            }
        }
        storyContext.put(RETRIEVE_RTP_RESPONSE, Nullable.nullable(retrieveRTPResponse));
    }


    @Then("AP Core retrieves the transaction associated with the received valid BRN")
    public void thenAPSendsPaymentNotification() {

    }

    @Then("the Consumer is identified and associated with the transaction")
    public void thenConsumerAssociatedTransaction() {

    }

    @Then("a succesful response message is to be created and sent to OSB")
    public void thenSuccessfulResponseCreated() {
        doRetrieveRTPResponseAssertions(Nullable.nullable(storyContext.get(RTP_SUMMARY)), Nullable.nullable(storyContext.get(RTP_SENDER_INFO)), Nullable.nullable(storyContext.get(RTP_MSGTYPE)));
    }

    @Then("a succesful response message which includes emailaddress of the consumer is to be created and sent to OSB")
    public void thenSuccessfulResponseCreatedwithEmail() {
        doRetrieveRTPResponseAssertions(Nullable.nullable(storyContext.get(RTP_SUMMARY)), Nullable.nullable(storyContext.get(RTP_SENDER_INFO)), Nullable.nullable(storyContext.get(RTP_MSGTYPE)));

        Nullable<RetrieveRTP1Response> retrieveRTP1Response = storyContext.get(RETRIEVE_RTP_RESPONSE);
        assertThat("emailaddress is null", false, CoreMatchers.is(CoreMatchers.equalTo(retrieveRTP1Response.value().getDelivery().getEmailAddress()== null)));
    }

    @Then("the status of the RTP is updated to AWAITING_PAYMENT_CONFIRMATION")
    public void thenRTPRetrieved() {
    }



    @Given("the Consumer confirms the address on the FI App and authorises the payment")
    public void giveConsumerConfirmsAddressInMobileApp() throws Exception {

    }


    @When("the Consumer's FI sends a successful structurally valid payment confirmation to AP Core")
    public void whenAPReceivesValidConfirmPaymentRequest() throws Exception {
        processConfirmPaymentMessage();
    }



    @Then("a successful message is to be created and sent to OSB")
    public void thenAPSendsMessageToOSB() {
        doConfirmPaymentResponseAssertions(storyContext.get(CONFIRM_PAYMENT_RESPONSE), confirmPayment1Request, submitRTPRequest);

    }

    @Then("a successful message with consumers mail address is to be created and sent to OSB")
    public void thenAPSendsMessageToOSBwithEmail() {
        doConfirmPaymentResponseAssertions(storyContext.get(CONFIRM_PAYMENT_RESPONSE), confirmPayment1Request, submitRTPRequest);

        Nullable<ConfirmPayment1Response> confirmPayment1Response = storyContext.get(CONFIRM_PAYMENT_RESPONSE);
        assertThat("emailaddress is null", false, CoreMatchers.is(CoreMatchers.equalTo(confirmPayment1Response.value().getQuickpayDel().getQkPayDelEmail() == null)));


    }

    @Then("the status of the RTP is updated to AUTHORISED")
    public void thenRTP_StatusRTP_COMPLETED() {

    }

    private void processConfirmPaymentMessage() throws ConfirmPayment1Fault {
        final ManagePayment1PortType managePayment1PortType = factory.getBean(ManagePayment1PortType.class);

        Nullable<RetrieveRTP1Response> retrieveRTPResponse = storyContext.get(RETRIEVE_RTP_RESPONSE);

        confirmPayment1Request = createConfirmPayment1Request(MessageType.CONFIRMPAYMENT, TransactionCheckOutType.QKPACHK, submitRTPRequest.getDelivery().getDeliveryType());

        confirmPayment1Request.getPaymtDetails().setApTransactionId(retrieveRTPResponse.value().getRTPIdentifier().getApTransactionId());
        confirmPayment1Request.getPaymtDetails().setApTRId(retrieveRTPResponse.value().getRTPIdentifier().getApTRId());

        confirmPayment1Request.getConsumerAcct().setFIId(retrieveRTPResponse.value().getConsumerInfo().getFIId());

        if(DeliveryType.DIGDEL.equals(submitRTPRequest.getDelivery().getDeliveryType())){
            confirmPayment1Request.getPaymtDetails().setQkPayDelAddress(null);
        }
        
        confirmPayment1Request.getPaymtDetails().getPaymentStatusInfo().setTotalPaymentReqAmount(retrieveRTPResponse.value().getRTPSummary().getPaymtAmtInfo().getTotalPaymentReqAmount());

        JaxbUtil.newInstance().javaToXML(ConfirmPayment1Request.class, confirmPayment1Request);

        ConfirmPayment1Response confirmPayment1Response = managePayment1PortType.confirmPayment1(confirmPayment1Request);

        JaxbUtil.newInstance().javaToXML(ConfirmPayment1Response.class, confirmPayment1Response);

        storyContext.put(CONFIRM_PAYMENT_RESPONSE, Nullable.nullable(confirmPayment1Response));
    }

}
